﻿using System;
using MathService.Values;

namespace MathService.Statistic.RandomNumbers
{
    /// <summary>Генератор случайных чисел</summary>
    [Serializable]
    public abstract class RandomGenerator : IValueRead<double>
    {
        /// <summary>Датчик случайных чисел с равномерным распределением</summary>
        protected static readonly LazyValue<Random> SystemRandomGenerator =
            new LazyValue<Random>(() => new Random(DateTime.Now.TimeOfDay.Milliseconds));

        /* ------------------------------------------------------------------------------------------ */

        /// <summary>Дисперсия</summary>
        protected double f_D = 1;
        /// <summary>Математическое ожидание</summary>
        protected double f_m;

        /* ------------------------------------------------------------------------------------------ */

        /// <summary>Дисперсия</summary>
        public double D { get { return f_D; } set { f_D = value; } }

        /// <summary>Математическое ожидание</summary>
        public double m { get { return f_m; } set { f_m = value; } }

        /// <summary>Случайное значение</summary>
        public double Value { get { return GetValue(); } }

        /* ------------------------------------------------------------------------------------------ */

        protected RandomGenerator() { }

        protected RandomGenerator(double D) { f_D = D; }

        protected RandomGenerator(double D, double m) { f_D = D; f_m = m; }

        /* ------------------------------------------------------------------------------------------ */

        /// <summary>Новое случайное число</summary><returns>Случайное число</returns>
        protected virtual double GetValue() { return GetValue(f_D, f_m); }

        public virtual double GetValue(double sigma2, double m) { return GetNextValue() * sigma2 + m; }

        protected abstract double GetNextValue();

        /* ------------------------------------------------------------------------------------------ */

        public static implicit operator double(RandomGenerator rnd) { return rnd.GetValue(); }

        /* ------------------------------------------------------------------------------------------ */
    }
}
